package cloudeval.spec

import cn.edu.neu.vmmigeval.cloud.entity.DataCenter
import cn.edu.neu.vmmigeval.cloud.entity.Host
import cn.edu.neu.vmmigeval.cloud.entity.PE

import java.util.concurrent.atomic.AtomicInteger

/**
 * The host cluster specification.
 *
 * @author yfwz100
 */
class HostClusterSpec {

    class HostSpec {

        private int freq, cores, ram, disk, bw
        private AtomicInteger counter = new AtomicInteger()

        void cpuFreq(int freq) {
            this.freq = freq
        }

        void cpuCores(int cores) {
            this.cores = cores
        }

        void ram(int ram) {
            this.ram = ram
        }

        void disk(int disk) {
            this.disk = disk
        }

        void bandwidth(int bw) {
            this.bw = bw
        }

        Host toHost() {
            PE pe = new PE(freq)
            List<PE> pes = new ArrayList<>()
            for (int i = 0; i < cores; i++) {
                pes.add(pe)
            }
            new Host(counter.incrementAndGet(), pes, pes.size() * freq, ram, bw, disk, null)
        }
    }

    private Map<Integer, HostSpec> hostMap = new HashMap()

    /**
     * Defines the hosts.
     *
     * @param size the size.
     * @param closure the host to create.
     * @return the host specification.
     */
    HostSpec Hosts(int size, @DelegatesTo(HostSpec) Closure closure) {
        def spec = new HostSpec()
        def code = closure.rehydrate(spec, this, this)
        code.resolveStrategy = Closure.DELEGATE_ONLY
        code()
        hostMap.put(size, spec)
        return spec
    }

    /**
     * Generate a data center entity.
     *
     * @return the data center entity.
     */
    DataCenter createDataCenter() {
        List<Host> hosts = new ArrayList<>()
        hostMap.each { size, hostSpec ->
            for (int i=0; i<size; i++) {
                hosts.add hostSpec.toHost()
            }
        }
        DataCenter dataCenter = new DataCenter()
        dataCenter.hosts = hosts
        return dataCenter
    }
}
